//----------------------------------Include-------------------------------------
#include "mcu.h"
#include "glbvar.h"
//------------------------------------------------------------------------------

//ADC 时钟包括 ADC 控制器时钟和 ADC 转换时钟（ ADC 转换时钟是 ADC 逐次逼近转换节拍控制的时钟）
//ADC 控制器时钟由系统控制模块配置，默认为系统总线时钟 200MHz
//ADC 转换时钟由 ADC 控制器时钟经过预分频得到：
//    设置 CONVCFG1[CONVCLKDIV] 寄存器位，配置 ADC 转换时钟相对于 ADC 控制器时钟的预分频的值
//    CONVCFG1[CONVCLKDIV] 值为 0 时，代表预分频值为/1；值为 1 时，预分频值为/2，最大为/16
//    ADC16 转换时钟最大频率为 50MHz

//读取转换模式 oneshot  : 用户读取 BUS_RESULTx 寄存器时，就会触发一次对 ADC 输入 x 的转换，待转换完成以后，直接返回结果
//周期转换模式 period   : 通过 PRD_CFGx[PRD_CNT] 和 [PRESCALE] 寄存器位设置周期的长度。周期转换的结果保存在 PRD_RESULTx 寄存器里
//序列转换模式 sequence : 按照预先编好的顺序，对指定的输入通道逐一转换
//抢占转换模式 preemption: 抢占转换是优先级最高的转换模式。适用于电机控制系统

//ADC16 相关寄存器 (ADC16_ 开头的寄存器，偏移量大于等于 0x1400)，需要配置如下寄存器才能正常写入：
//设置 CONV_CFG1 寄存器 CLK_DIVIDER=1
//设置 ANA_CTRL0 寄存器 ADC_CLK_ON=1

//PB15    ADC0_IN7 /ADC1_IN7
//PB14    ADC0_IN6 /ADC1_IN6
//PB13    ADC0_IN5 /ADC1_IN5
//PB12    ADC0_IN4 /ADC1_IN4
//PB11    ADC0_IN3 /ADC1_IN3
//PB10    ADC0_IN2 /ADC1_IN2
//PB09    ADC0_IN1 /ADC1_IN1
//PB08    ADC0_IN11/ADC1_IN11
//PB07    ADC0_IN10/ADC1_IN10
//PB06    ADC0_IN9 /ADC1_IN9
//PB05    ADC0_IN13/ADC1_IN13
//PB04    ADC0_IN0 /ADC1_IN0
//PB03    ADC0_IN8 /ADC1_IN8
//PB02    ADC0_IN12/ADC1_IN12
//PB01    ADC0_IN14/ADC1_IN14
//PB00    ADC0_IN15/ADC1_IN15

//-----------------------------------Macro--------------------------------------
#define _ADC_INST            HPM_ADC0
#define _INT_IRQn            IRQn_ADC0
//------------------------------------------------------------------------------
#define _DMA_EN              1
//------------------------------------------------------------------------------
#define _SAMP_LEN            GM_SAMP_LEN
#define _ADC_VREF            (3.3)
//------------------------------------------------------------------------------
#define _CHN_N               (1)
//------------------------------------------------------------------------------

//--------------------------------Static Var------------------------------------
static uint32_t    adc_ctrl_clk;
static uint32_t    adc_conv_clk;
//------------------------------------------------------------------------------
//DMA 每次会向内存写入 32 位（4 字节）数据，其中 16 位的 AD 转换结果位于 [15:0]，
//位 [31:16] 还包括了周期，序列编号，AD 输入通道序号等标志数据，方便软件解读 AD 转换的信息
ATTR_PLACE_AT_NONCACHEABLE_WITH_ALIGNMENT(ADC_SOC_DMA_ADDR_ALIGNMENT) uint32_t nu32_ad_cache[_SAMP_LEN];
//------------------------------------------------------------------------------

//--------------------------------Extern Var------------------------------------
//------------------------------------------------------------------------------

//--------------------------------Static Func-----------------------------------
//------------------------------------------------------------------------------

//------------------------------------ISR---------------------------------------
SDK_DECLARE_EXT_ISR_M(_INT_IRQn, _isr_adc16);

static  uint32_t  status;
static  uint16_t  data;
void _isr_adc16(void)
{
  status = adc16_get_status_flags(_ADC_INST);
  adc16_clear_status_flags(_ADC_INST, status);  /* Clear status */

#if _DMA_EN == 1
  if( ADC16_INT_STS_SEQ_DMAABT_GET(status) ){
    igu32_bufflag = 1;
    for(uint32_t i=0; i<_SAMP_LEN; i++){
      igaf_adc_u[i] = (float)(nu32_ad_cache[i]&0xFFFF)*(_ADC_VREF/65536);
    }
    
    //next start
    _ADC_INST->SEQ_DMA_CFG |=  ADC16_SEQ_DMA_CFG_DMA_RST_MASK;    //Reset
    _ADC_INST->SEQ_DMA_CFG &= ~ADC16_SEQ_DMA_CFG_DMA_RST_MASK;    //De-reset
  }
#else
  if (ADC16_INT_STS_SEQ_CVC_GET(status)) {
    adc16_get_prd_result(_ADC_INST, 5, &data);

    static uint32_t   cnt;
    igaf_adc_u[cnt] = (float)(data)*(_ADC_VREF/65536);
    if(++cnt >= _SAMP_LEN){
      cnt = 0;
      igu32_bufflag = 1;
    }
  }
#endif
}
//------------------------------------------------------------------------------

//--------------------------------Public Func-----------------------------------
void mcu_init_adc0(void)
{
//power
  
//pin
  //PB13--ADC0.5/ADC1.5
  HPM_IOC->PAD[IOC_PAD_PB13].FUNC_CTL = IOC_PAD_FUNC_CTL_ANALOG_MASK;

//adc
  //clk
  /* Configure the ADC clock from AHB (@200MHz by default)*/
  clock_set_adc_source(clock_adc0, clk_adc_src_ahb0);
  adc_ctrl_clk = clock_get_frequency(clock_adc0);

  //common
  adc16_config_t            cfg;
  adc16_get_default_config(&cfg);
  cfg.res            = adc16_res_16_bits;
  cfg.conv_mode      = adc16_conv_mode_sequence;
  cfg.adc_clk_div    = adc16_clock_divider_4;       adc_conv_clk = adc_ctrl_clk/4;
  cfg.sel_sync_ahb   = (clk_adc_src_ahb0 == clock_get_source(clock_adc0)) ? true : false;
  if (cfg.conv_mode == adc16_conv_mode_sequence || cfg.conv_mode == adc16_conv_mode_preemption) {
    cfg.adc_ahb_en = true;
  }
  adc16_init(_ADC_INST, &cfg);

  //channel
  adc16_channel_config_t            ch_cfg;
  adc16_get_channel_default_config(&ch_cfg);
  ch_cfg.ch                 = 5;
  ch_cfg.sample_cycle_shift = 2;     //SAMPLE_CFGx[SAMPLE_CLOCK_NUMBER_SHIFT]
  ch_cfg.sample_cycle       = 100U;  //SAMPLE_CFGx[SAMPLE_CLOCK_NUMBER]
  //采样时间为 SAMPLE_CLOCK_NUMBER x 2^(SAMPLE_CLOCK_NUMBER_SHIFT) 个时钟周期
  adc16_init_channel(_ADC_INST, &ch_cfg);

#if 0
  //period mode
  clk_div    = 2<<15;
  req_freqHz = 1000;
  period_cnt = (src_clk/clk_div)/req_freqHz;

  adc16_prd_config_t    prd_cfg;
  prd_cfg.ch           = 5;
  prd_cfg.prescale     = 15-1;        //same as clk_div
  prd_cfg.period_count = period_cnt;  //8bits  0 表示关闭周期模式
  adc16_set_prd_config(_ADC_INST, &prd_cfg);
#endif

  //sequence mode
  adc16_seq_config_t   seq_cfg;
  seq_cfg.seq_len    = 1;       //SEQ_CFG0 [SEQ_LEN] 位指定转换序列的长度，最长可达 16
  seq_cfg.restart_en = false;   //注意 restart 和 continue 两者的配合
  seq_cfg.cont_en    = true;    //多通道连续转换
  seq_cfg.hw_trig_en = false;
  seq_cfg.sw_trig_en = true;    //5301基础款没有trigger mux, 只能软件触发。5361才有
  //初始化序列里的各项，多于一个可用循环
  seq_cfg.queue[0].seq_int_en = false;
  seq_cfg.queue[0].ch         = 5;
  //序列的最后一项使能中断(但是形成中断需要中断使能配合)
  seq_cfg.queue[seq_cfg.seq_len - 1].seq_int_en = true;
  adc16_set_seq_config(_ADC_INST, &seq_cfg);
  
#if _DMA_EN == 1
  adc16_dma_config_t  dma_cfg;
  dma_cfg.start_addr         = (uint32_t *)core_local_mem_to_sys_address(HPM_CORE0, (uint32_t)nu32_ad_cache);  //adc的DMA步长固定4字节
  dma_cfg.buff_len_in_4bytes = _SAMP_LEN;
  dma_cfg.stop_en            = true;           //停止使能
  dma_cfg.stop_pos           = _SAMP_LEN -1;   //(注意减1) DMA 在指针到达 SEQ_DMA_ADDR + STOP_POS 后停止，标志位 INT_STS [SEQ_DMAABT]会置 1
  adc16_init_seq_dma(_ADC_INST, &dma_cfg);
//interrupt
  adc16_enable_interrupts(_ADC_INST, adc16_event_seq_dma_abort);
  intc_m_enable_irq_with_priority(_INT_IRQn, 6);
#else
//interrupt
  adc16_enable_interrupts(_ADC_INST, adc16_event_seq_full_complete);
  intc_m_enable_irq_with_priority(_INT_IRQn, 6);
#endif
}

//soft trigger
void mcu_adc0_sw_trig(void)
{
  adc16_trigger_seq_by_sw(_ADC_INST);
}
//------------------------------------EOF---------------------------------------





